home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
os2
/
timidsrc.zip
/
ncurs_c.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-21
|
12KB
|
541 lines
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
ncurs_c.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <ncurses.h>
#include "config.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "output.h"
#include "controls.h"
static void ctl_refresh(void);
static void ctl_help_mode(void);
static void ctl_total_time(int tt);
static void ctl_master_volume(int mv);
static void ctl_file_name(char *name);
static void ctl_current_time(int ct);
static void ctl_note(int v);
static void ctl_program(int ch, int val);
static void ctl_volume(int channel, int val);
static void ctl_expression(int channel, int val);
static void ctl_panning(int channel, int val);
static void ctl_sustain(int channel, int val);
static void ctl_pitch_bend(int channel, int val);
static void ctl_reset(void);
static int ctl_open(int using_stdin, int using_stdout);
static void ctl_close(void);
static int ctl_read(int32 *valp);
static int cmsg(int type, int verbosity_level, char *fmt, ...);
/**********************************************/
/* export the interface functions */
#define ctl ncurses_control_mode
ControlMode ctl=
{
"ncurses interface", 'n',
1,0,0,
ctl_open,dumb_pass_playing_list, ctl_close, ctl_read, cmsg,
ctl_refresh, ctl_reset, ctl_file_name, ctl_total_time, ctl_current_time,
ctl_note,
ctl_master_volume, ctl_program, ctl_volume,
ctl_expression, ctl_panning, ctl_sustain, ctl_pitch_bend
};
/***********************************************************************/
/* foreground/background checks disabled since switching to curses */
/* static int in_foreground=1; */
static int ctl_helpmode=0;
static WINDOW *dftwin=0, *msgwin=0;
static void _ctl_refresh(void)
{
wmove(dftwin, 0,0);
wrefresh(dftwin);
}
static void ctl_refresh(void)
{
if (ctl.trace_playing)
_ctl_refresh();
}
static void ctl_help_mode(void)
{
static WINDOW *helpwin;
if (ctl_helpmode)
{
ctl_helpmode=0;
delwin(helpwin);
touchwin(dftwin);
_ctl_refresh();
}
else
{
ctl_helpmode=1;
/* And here I thought the point of curses was that you could put
stuff on windows without having to worry about whether this
one is overlapping that or the other way round... */
helpwin=newwin(2,COLS,0,0);
wattron(helpwin, A_REVERSE);
werase(helpwin);
waddstr(helpwin,
"V/Up=Louder b/Left=Skip back "
"n/Next=Next file r/Home=Restart file");
wmove(helpwin, 1,0);
waddstr(helpwin,
"v/Down=Softer f/Right=Skip forward "
"p/Prev=Previous file q/End=Quit program");
wrefresh(helpwin);
}
}
static void ctl_total_time(int tt)
{
int mins, secs=tt/play_mode->rate;
mins=secs/60;
secs-=mins*60;
wmove(dftwin, 4,6+6+3);
wattron(dftwin, A_BOLD);
wprintw(dftwin, "%3d:%02d", mins, secs);
wattroff(dftwin, A_BOLD);
_ctl_refresh();
}
static void ctl_master_volume(int mv)
{
wmove(dftwin, 4,COLS-5);
wattron(dftwin, A_BOLD);
wprintw(dftwin, "%03d %%", mv);
wattroff(dftwin, A_BOLD);
_ctl_refresh();
}
static void ctl_file_name(char *name)
{
wmove(dftwin, 3,6);
wclrtoeol(dftwin );
wattron(dftwin, A_BOLD);
waddstr(dftwin, name);
wattroff(dftwin, A_BOLD);
_ctl_refresh();
}
static void ctl_current_time(int ct)
{
int i,v;
int mins, secs=ct/play_mode->rate;
if (!ctl.trace_playing)
return;
mins=secs/60;
secs-=mins*60;
wmove(dftwin, 4,6);
wattron(dftwin, A_BOLD);
wprintw(dftwin, "%3d:%02d", mins, secs);
v=0;
i=voices;
while (i--)
if (voice[i].status!=VOICE_FREE) v++;
wmove(dftwin, 4,48);
wprintw(dftwin, "%2d", v);
wattroff(dftwin, A_BOLD);
_ctl_refresh();
}
static void ctl_note(int v)
{
int xl;
if (!ctl.trace_playing)
return;
xl=voice[v].note%(COLS-24);
wmove(dftwin, 8+voice[v].channel,xl+3);
switch(voice[v].status)
{
case VOICE_DIE:
waddch(dftwin, ',');
break;
case VOICE_FREE:
waddch(dftwin, '.');
break;
case VOICE_ON:
wattron(dftwin, A_BOLD);
waddch(dftwin, '0'+(10*voice[v].velocity)/128);
wattroff(dftwin, A_BOLD);
break;
case VOICE_OFF:
case VOICE_SUSTAINED:
waddch(dftwin, '0'+(10*voice[v].velocity)/128);
break;
}
}
static void ctl_program(int ch, int val)
{
if (!ctl.trace_playing)
return;
wmove(dftwin, 8+ch, COLS-20);
if (ISDRUMCHANNEL(ch))
{
wattron(dftwin, A_BOLD);
wprintw(dftwin, "%03d", val);
wattroff(dftwin, A_BOLD);
}
else
wprintw(dftwin, "%03d", val);
}
static void ctl_volume(int channel, int val)
{
if (!ctl.trace_playing)
return;
wmove(dftwin, 8+channel, COLS-16);
wprintw(dftwin, "%3d", (val*100)/127);
}
static void ctl_expression(int channel, int val)
{
if (!ctl.trace_playing)
return;
wmove(dftwin, 8+channel, COLS-12);
wprintw(dftwin, "%3d", (val*100)/127);
}
static void ctl_panning(int channel, int val)
{
if (!ctl.trace_playing)
return;
wmove(dftwin, 8+channel, COLS-8);
if (val==NO_PANNING)
waddstr(dftwin, " ");
else if (val<5)
waddstr(dftwin, " L ");
else if (val>123)
waddstr(dftwin, " R ");
else if (val>60 && val<68)
waddstr(dftwin, " C ");
else
{
/* wprintw(dftwin, "%+02d", (100*(val-64))/64); */
val = (100*(val-64))/64; /* piss on curses */
if (val<0)
{
waddch(dftwin, '-');
val=-val;
}
else waddch(dftwin, '+');
wprintw(dftwin, "%02d", val);
}
}
static void ctl_sustain(int channel, int val)
{
if (!ctl.trace_playing)
return;
wmove(dftwin, 8+channel, COLS-4);
if (val) waddch(dftwin, 'S');
else waddch(dftwin, ' ');
}
static void ctl_pitch_bend(int channel, int val)
{
if (!ctl.trace_playing)
return;
wmove(dftwin, 8+channel, COLS-2);
if (val>0x2000) waddch(dftwin, '+');
else if (val<0x2000) waddch(dftwin, '-');
else waddch(dftwin, ' ');
}
static void ctl_reset(void)
{
int i,j;
if (!ctl.trace_playing)
return;
for (i=0; i<16; i++)
{
wmove(dftwin, 8+i, 3);
for (j=0; j<COLS-24; j++)
waddch(dftwin, '.');
ctl_program(i, channel[i].program);
ctl_volume(i, channel[i].volume);
ctl_expression(i, channel[i].expression);
ctl_panning(i, channel[i].panning);
ctl_sustain(i, channel[i].sustain);
ctl_pitch_bend(i, channel[i].pitchbend);
}
_ctl_refresh();
}
/***********************************************************************/
/* #define CURSED_REDIR_HACK */
#ifdef CURSED_REDIR_HACK
static SCREEN *oldscr;
#endif
static int ctl_open(int using_stdin, int using_stdout)
{
int i;
#ifdef CURSED_REDIR_HACK
FILE *infp=stdin, *outfp=stdout;
SCREEN *dftscr;
/* This doesn't work right */
if (using_stdin && using_stdout)
{
infp=outfp=stderr;
fflush(stderr);
setvbuf(stderr, 0, _IOFBF, BUFSIZ);
}
else if (using_stdout)
{
outfp=stderr;
fflush(stderr);
setvbuf(stderr, 0, _IOFBF, BUFSIZ);
}
else if (using_stdin)
{
infp=stdout;
fflush(stdout);
setvbuf(stdout, 0, _IOFBF, BUFSIZ);
}
dftscr=newterm(0, outfp, infp);
if (!dftscr)
return -1;
oldscr=set_term(dftscr);
/* dftwin=stdscr; */
#else
initscr();
#endif
cbreak();
noecho();
nonl();
nodelay(stdscr, 1);
scrollok(stdscr, 0);
idlok(stdscr, 1);
keypad(stdscr, TRUE);
ctl.opened=1;
if (ctl.trace_playing)
dftwin=stdscr;
else
dftwin=newwin(6,COLS,0,0);
werase(dftwin);
wmove(dftwin, 0,0);
waddstr(dftwin, "TiMidity v" TIMID_VERSION);
wmove(dftwin, 0,COLS-52);
waddstr(dftwin, "(C) 1995 Tuukka Toivonen <toivonen@clinet.fi>");
wmove(dftwin, 1,0);
waddstr(dftwin, "Press 'h' for help with keys, or 'q' to quit.");
wmove(dftwin, 3,0);
waddstr(dftwin, "File:");
wmove(dftwin, 4,0);
if (ctl.trace_playing)
{
waddstr(dftwin, "Time:");
wmove(dftwin, 4,6+6+1);
waddch(dftwin, '/');
wmove(dftwin, 4,40);
wprintw(dftwin, "Voices: / %d", voices);
}
else
{
waddstr(dftwin, "Playing time:");
}
wmove(dftwin, 4,COLS-20);
waddstr(dftwin, "Master volume:");
wmove(dftwin, 5,0);
for (i=0; i<COLS; i++)
waddch(dftwin, '_');
if (ctl.trace_playing)
{
wmove(dftwin, 6,0);
waddstr(dftwin, "Ch");
wmove(dftwin, 6,COLS-20);
waddstr(dftwin, "Prg Vol Exp Pan S B");
wmove(dftwin, 7,0);
for (i=0; i<COLS; i++)
waddch(dftwin, '-');
for (i=0; i<16; i++)
{
wmove(dftwin, 8+i, 0);
wprintw(dftwin, "%02d", i+1);
}
}
else
{
msgwin=newwin(LINES-6,COLS,6,0);
werase(msgwin);
scrollok(msgwin, 1);
wrefresh(msgwin);
}
_ctl_refresh();
return 0;
}
static void ctl_close(void)
{
if (ctl.opened)
{
endwin();
ctl.opened=0;
}
}
static int ctl_read(int32 *valp)
{
int c;
while ((c=getch())!=ERR)
{
switch(c)
{
case 'h':
case '?':
case KEY_F(1):
ctl_help_mode();
return RC_NONE;
case 'V':
case KEY_UP:
*valp=10;
return RC_CHANGE_VOLUME;
case 'v':
case KEY_DOWN:
*valp=-10;
return RC_CHANGE_VOLUME;
case 'q':
case KEY_END:
return RC_QUIT;
case 'n':
case KEY_NPAGE:
return RC_NEXT;
case 'p':
case KEY_PPAGE:
return RC_REALLY_PREVIOUS;
case 'r':
case KEY_HOME:
return RC_RESTART;
case 'f':
case KEY_RIGHT:
*valp=play_mode->rate;
return RC_FORWARD;
case 'b':
case KEY_LEFT:
*valp=play_mode->rate;
return RC_BACK;
/* case ' ':
return RC_TOGGLE_PAUSE; */
}
}
return RC_NONE;
}
static int cmsg(int type, int verbosity_level, char *fmt, ...)
{
va_list ap;
if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
ctl.verbosity<verbosity_level)
return 0;
va_start(ap, fmt);
if (!ctl.opened)
{
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
else if (ctl.trace_playing)
{
switch(type)
{
/* Pretty pointless to only have one line for messages, but... */
case CMSG_WARNING:
case CMSG_ERROR:
case CMSG_FATAL:
wmove(dftwin, 2,0);
wclrtoeol(dftwin);
wattron(dftwin, A_REVERSE);
vwprintw(dftwin, fmt, ap);
wattroff(dftwin, A_REVERSE);
_ctl_refresh();
if (type==CMSG_WARNING)
sleep(1); /* Don't you just _HATE_ it when programs do this... */
else
sleep(2);
wmove(dftwin, 2,0);
wclrtoeol(dftwin);
_ctl_refresh();
break;
}
}
else
{
switch(type)
{
default:
vwprintw(msgwin, fmt, ap);
wprintw(msgwin, "\n");
wrefresh(msgwin);
break;
case CMSG_WARNING:
wattron(msgwin, A_BOLD);
vwprintw(msgwin, fmt, ap);
wprintw(msgwin, "\n");
wattroff(msgwin, A_BOLD);
wrefresh(msgwin);
break;
case CMSG_ERROR:
case CMSG_FATAL:
wattron(msgwin, A_REVERSE);
vwprintw(msgwin, fmt, ap);
wprintw(msgwin, "\n");
wattroff(msgwin, A_REVERSE);
wrefresh(msgwin);
if (type==CMSG_FATAL)
sleep(2);
break;
}
}
va_end(ap);
return 0;
}